package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.WemediaConstants;
import com.heima.common.constants.WmNewsMessageConstants;
import com.heima.common.exception.CustomException;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import com.heima.wemedia.service.WmNewsService;
import com.heima.wemedia.service.WmNewsTaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author ZQH
 * @version 1.0
 * @date 2023/7/31 21:51
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {
    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Override
    public ResponseResult findAll(WmNewsPageReqDto pageReqDto) {
        //检查参数
        if (StringUtils.isEmpty(pageReqDto)){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        pageReqDto.checkParam();

        //获取登录人信息
        WmUser user = WmThreadLocalUtil.getUser();
        //分页查询
        IPage iPage = new Page(pageReqDto.getPage(),pageReqDto.getSize());
        IPage page = wmNewsMapper.selectPage(iPage, Wrappers.<WmNews>lambdaQuery()
                .eq(WmNews::getUserId, user.getId())
                .eq(!StringUtils.isEmpty(pageReqDto.getStatus()), WmNews::getStatus, pageReqDto.getStatus())
                .eq(!StringUtils.isEmpty(pageReqDto.getChannelId()), WmNews::getChannelId, pageReqDto.getChannelId())
                .between(!StringUtils.isEmpty(pageReqDto.getBeginPubDate()),WmNews::getPublishTime,pageReqDto.getBeginPubDate(),pageReqDto.getEndPubDate())
                .like(!StringUtils.isEmpty(pageReqDto.getKeyword()), WmNews::getTitle, pageReqDto.getKeyword())
                .orderByDesc(WmNews::getCreatedTime)
        );
        ResponseResult responseResult = new PageResponseResult(pageReqDto.getPage(),pageReqDto.getSize(), (int) page.getTotal());
        responseResult.setData(page.getRecords());
        return responseResult;
    }


    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;
    @Autowired
    private WmNewsAutoScanService wmNewsAutoScanService;

    @Autowired
    private WmNewsTaskService wmNewsTaskService;



    /**
     * 发布修改文章，或保存为草稿
     * @param wmNewsDto
     * @return
     */
    @Override
    public ResponseResult submitNews(WmNewsDto wmNewsDto) {
        //条件判断
        if (StringUtils.isEmpty(wmNewsDto) || StringUtils.isEmpty(wmNewsDto.getContent())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //保存或修改文章
        WmNews wmNews = new WmNews();
        //内容拷贝
        BeanUtils.copyProperties(wmNewsDto,wmNews);
        if (wmNewsDto.getImages() !=null && wmNewsDto.getImages().size()>0){
            String join = org.apache.commons.lang3.StringUtils.join(wmNewsDto.getImages(), ",");
            wmNews.setImages(join);
        }
        //如果当前封类型为自动 -1
        if (wmNewsDto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)){
            wmNews.setType(null);
        }

        saveOrUpdateWmNews(wmNews);
        //判断是否为草稿
        if (wmNewsDto.getStatus().equals(WmNews.Status.NORMAL.getCode())){
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }

        //不是草稿，保存文章内容图片与素材的关系wm_material
        //获取到文章内容的图片信息
        List<String> material =  ectractUrlInfo(wmNewsDto.getContent());
        saveRelativeInfoForContent(material,wmNews.getId());


        //不是草稿，保存文章封面图片与素材的关系,如果当前布局是自动，需要匹配封面图片 wm_news_material
        saveRelativeInfoForCover(wmNewsDto,wmNews,material);
        //审核
//        wmNewsAutoScanService.autoScanWmNews(wmNews .getId());
        //添加 到延迟任务队列
        wmNewsTaskService.addNewsToTask(wmNews.getId(),wmNews.getPublishTime());

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 如果当前封面类型是自动，则设置封面类型的数据
     * 匹配规则
     * 1、如果内容图片>=1  <3 单图  type=1
     * 2、如果内容图片>=3  多图 type = 3
     * 3、如果内容没有图片  无图，tupe = 0
     *
     * 第二部：保存封面图片与素材的关系
     * @param wmNewsDto
     * @param material
     */
    private void saveRelativeInfoForCover(WmNewsDto wmNewsDto,WmNews wmNews, List<String> material) {
        List<String> images = wmNewsDto.getImages();
        //如果当前封面类型为自动，则设置封面类型的数据
        if (WemediaConstants.WM_NEWS_TYPE_AUTO.equals(wmNewsDto.getImages())){
            //多图
            if(material.size()>=3){
                wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
                images = material.stream().limit(3).collect(Collectors.toList());

            }else if (material.size()>=1 &&material.size()<3){
                //单图
                wmNews.setType(WemediaConstants.WM_COVER_REFERENCE);
                images = material.stream().limit(1).collect(Collectors.toList());
            }else {
                //无图
                wmNews.setType(WemediaConstants.CANCEL_COLLECT_MATERIAL);
            }
            //修改文章
            if (!StringUtils.isEmpty(images)){
                wmNews.setImages(org.apache.commons.lang.StringUtils.join(images,","));
            }
            this.updateById(wmNews);
        }
        //第二步：保存封面图片与素材的关系
        if (!StringUtils.isEmpty(images)){
            saveRelativeInfo(images,wmNews.getId(),WemediaConstants.WM_COVER_REFERENCE);
        }


    }

    /**
     * 保存文章内容图片与素材的关系
     * @param material
     */
    private void saveRelativeInfoForContent(List<String> material,Integer newsId) {
        saveRelativeInfo(material,newsId,WemediaConstants.CANCEL_COLLECT_MATERIAL);
    }


    @Autowired
    private WmMaterialMapper wmMaterialMapper;
    /**
     * 保存文章图片与素材的关系
     * @param material 素材url
     * @param newsId    文章ID
     * @param type 引用类型  0 内容引用 1 主图引用
     */
    private void saveRelativeInfo(List<String> material, Integer newsId, Short type) {
        if (StringUtils.isEmpty(material)){
            //根据图片url查询素材ID
            List<WmMaterial> wmMaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery()
                    .in(WmMaterial::getUrl, material));
            //判断是否有素材
            if (StringUtils.isEmpty(wmMaterials)){
                //抛出异常 数据回滚保护数据一致性
                throw new CustomException(AppHttpCodeEnum.MATERIAL_REFERENCE_FAIL);
            }
            if (material.size() != wmMaterials.size()){
                throw new CustomException(AppHttpCodeEnum.MATERIAL_REFERENCE_FAIL);
            }
            //收集ID
            List<Integer> wmMaterialIds = wmMaterials.stream().map(WmMaterial::getId).collect(Collectors.toList());
            //批量保存
            wmNewsMaterialMapper.saveRelation(wmMaterialIds,newsId,type);
        }
    }

    /**
     * 获取到文章内容的图片信息
     * @param content
     * @return
     */
    private List<String> ectractUrlInfo(String content) {
        List<String> imgList = new ArrayList<>();
        List<Map> jsonArray = JSON.parseArray(content,Map.class);
        for (Map map : jsonArray) {
            if ("image".equals(map.get("type"))){
                String imgUrl = map.get("value").toString();
                imgList.add(imgUrl);
            }
        }
        return imgList;
    }

    /**
     * 保存或修改文章
     * @param wmNews
     */
    private void saveOrUpdateWmNews(WmNews wmNews) {
        //补全属性
        wmNews.setUserId(WmThreadLocalUtil.getUser().getId());
        wmNews.setCreatedTime(new Date());
        wmNews.setPublishTime(new Date());
        wmNews.setEnable((short) 1);
        //如果id为空 则添加操作
        if (StringUtils.isEmpty(wmNews.getId())){
            this.save(wmNews);
        }else{
            //不为空修改操作
            // 先删除文章图片关联素材关系
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
            .eq(WmNewsMaterial::getNewsId,wmNews.getId()));
            //修改
            this.updateById(wmNews);

        }
    }


    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;
    /**
     * 文章上下架
     *
     * @param wmNewsDto
     * @return
     */
    @Override
    public ResponseResult downOrUp(WmNewsDto wmNewsDto) {

        //检查参数
        if (wmNewsDto.getId() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //查询文章
        WmNews wmNews = this.getById(wmNewsDto.getId());
        if (!StringUtils.isEmpty(wmNews)){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"文章不存在");
        }
        //判断文章是否已发布
        if (!wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"当前文章未发布，不能上架或者下架！");
        }

        //修改文章
        if (wmNewsDto.getEnable() !=null && wmNewsDto.getEnable() > -1 && wmNewsDto.getEnable() < 2){
            boolean update = update(Wrappers.<WmNews>lambdaUpdate()
                    .set(WmNews::getEnable, wmNewsDto.getEnable())
                    .eq(WmNews::getId, wmNewsDto.getId()));
            Assert.isTrue(update,"上架或者下架失败，请重试！");

            if (wmNews.getArticleId() != null){
                //文章状态修改完成 发送消息 通知article修改文章配置
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("articleId",wmNews.getArticleId());
                jsonObject.put("enable",wmNewsDto.getEnable());
                kafkaTemplate.send(WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_TOPIC,
                        jsonObject.toJSONString());
            }

        }
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

}
